package readwritelock;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * 邮戳锁使用示例
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/09/12 下午 01:03
 */
public class StampedLockDemo {
    int data = 37;
    final StampedLock lock = new StampedLock();

    /**
     * 悲观读操作
     */
    public void read() {
        long stamp = lock.readLock();
        try {
            System.out.println("第一次读取，当前data=" + data);

            //等待4s，由于加了悲观读锁，写线程无法进入修改数据
            for (int i = 0; i < 4; i++) {
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                    System.out.println("读线程等待...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println("第二次读取，当前data=" + data);

        } finally {
            lock.unlockRead(stamp);
        }
    }

    /**
     * 乐观读操作
     */
    public void readOptimize() {
        //尝试乐观读
        long stamp = lock.tryOptimisticRead();
        int variable = data;

        //等待4s，期间写线程修改数据
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("调用valid()的结果：" + lock.validate(stamp));
        }


        if (!lock.validate(stamp)) {
            //加悲观读锁
            stamp = lock.readLock();
            try {
                variable = data;
                //悲观读成功，返回值
                System.out.println("悲观读到data=" + variable);
            } finally {
                lock.unlockRead(stamp);
            }
        } else {
            //乐观读成功，返回值
            System.out.println("乐观读到data=" + variable);
        }
    }

    public void write() {
        long stamp = lock.writeLock();

        try {
            data = 50;
            System.out.println("写入data=" + data);
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    //悲观读 + 写测试
    @Test
    public void test1() {


        new Thread(() -> {
            read();
        }).start();

        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            write();
        }).start();

        try {
            TimeUnit.MILLISECONDS.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //乐观读 + 写测试
    @Test
    public void test2() {

        new Thread(() -> {
//            read();
            readOptimize();
        }).start();

        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            write();
        }).start();

        try {
            TimeUnit.MILLISECONDS.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}


